#include "../Headers/log.h"

#include "../AR/authorization.h"

#include "ws.server.h"
#include "ws.request.h"

#include <fstream>
#include <string>

TOB::Config TOB::WS::WebServer::config = TOB::Config(WS_CONFIG);

TOB::WS::Packer* TOB::WS::WebServer::ExecRequest(TOB::WS::Unpacker& unpacker) {
  
  bool WSForbidden = false;
  TOB::Authorization auth(unpacker.getNSIP(), unpacker.getUsername(), unpacker.getPassword());
  Code::Type result = auth.WebServer(WSForbidden);
  if (result != Code::Okay) {
    TOB::WS::Data* tmpData = new TOB::WS::Data("Authorization error.");
    TOB::WS::Packer* tmpPacker = new TOB::WS::Packer("response://to.client", tmpData);
    if (tmpData != NULL) {
      delete tmpData;
    }
    return tmpPacker;
  }
  if (!WSForbidden) {
    TOB::WS::Data* tmpData = new TOB::WS::Data("Forbidden.");
    TOB::WS::Packer* tmpPacker = new TOB::WS::Packer("response://to.client", tmpData);
    if (tmpData != NULL) {
      delete tmpData;
    }
    return tmpPacker;
  }
  
  TOB::WS::Data* data;
  
  try {
    switch (unpacker.getFunc()) {
    
    case (TOB::WS::Function::GetPage):
      TOB::Log::event("Webserver: " + unpacker.getUsername() + " request page.");
      data = GetPage(unpacker);
      break;
      
    case (TOB::WS::Function::GetFile):
      TOB::Log::event("Webserver: " + unpacker.getUsername() + " request file.");
      data = GetFile(unpacker);
      break;
      
    case (TOB::WS::Function::SendFile):
      TOB::Log::event("Webserver: " + unpacker.getUsername() + " sended file.");
      data = SendFile(unpacker);
      break;
      
    default:
      data = NULL;
    }
  } catch (TOB::WS::WebServerException()) {
    return NULL;
  }
  
  TOB::WS::Packer* packer = NULL;
  try {
    packer = new TOB::WS::Packer("response://to.client", data);
  } catch (TOB::WS::PackerException) {
    return NULL;
  }
  
  if (data != NULL) {
    delete data;
  }
  
  return packer;
}



TOB::WS::Data* TOB::WS::WebServer::GetPage(TOB::WS::Unpacker& unpacker) {
  TOB::WS::Request* req = NULL;
  try {
    req = new TOB::WS::Request(unpacker.getRequest());
  } catch (RequestException) {
    throw TOB::WS::WebServerException("Parse error", Code::WS_ParseError);
  }
  std::string pathToFile = "./" + config.stringValue("rootdir") + "/" + req->getPathToFile();
  std::ifstream f;
  f.open(pathToFile);
  
  TOB::WS::Data* result;
  if (f.is_open()) {
    std::string line;
    std::string buffer;
    while (f.good()) {
      std::getline(f, line);
      buffer += line + "\n";
    }
    buffer.resize(buffer.length() - 1);
    f.close();
    result = new TOB::WS::Data(buffer);
  }
  else {
    result = new TOB::WS::Data("404. File (" + pathToFile + ") not found");
  }
  
  if (req != NULL) {
    delete req;
  }
  return result;
}



TOB::WS::Data* TOB::WS::WebServer::GetFile(TOB::WS::Unpacker& unpacker) {
  TOB::WS::Request* req = NULL;
  try {
    req = new TOB::WS::Request(unpacker.getRequest());
  } catch (RequestException) {
    throw TOB::WS::WebServerException("Parse error", Code::WS_ParseError);
  }
  std::string pathToFile = "./" + config.stringValue("rootdir") + "/" + req->getPathToFile();
  std::ifstream f;
  f.open(pathToFile);
  
  TOB::WS::Data* result;
  if (f.is_open()) {
    std::string line;
    std::string buffer;
    while (f.good()) {
      std::getline(f, line);
      buffer += line + "\n";
    }
    buffer.resize(buffer.length() - 1);
    f.close();
    result = new TOB::WS::Data(buffer);
  }
  else {
    result = new TOB::WS::Data("404. File (" + pathToFile + ") not found");
  }
  
  if (req != NULL) {
    delete req;
  }
  return result;
}



TOB::WS::Data* TOB::WS::WebServer::SendFile(TOB::WS::Unpacker& unpacker) {
  TOB::WS::Request* req = NULL;
  try {
    req = new TOB::WS::Request(unpacker.getRequest());
  } catch (RequestException) {
    throw TOB::WS::WebServerException("Parse error", Code::WS_ParseError);
  }
  std::string pathToFile = "./" + config.stringValue("rootdir") + "/" + req->getPathToFile();
  std::fstream f(pathToFile, std::ios::out | std::ios::app);
  
  TOB::WS::Data* result;
  if (f.is_open()) {
    f << unpacker.getData().getBuffer() << std::endl;
    result = new TOB::WS::Data("File (" + pathToFile + ") rewrote");
    f.close();
  }
  else {
    result = new TOB::WS::Data("Does not create file (" + pathToFile + ")");
  }
  
  if (req != NULL) {
    delete req;
  }
  return result;
}


TOB::WS::WebServerException::WebServerException(std::string msg, Code::Type error) {
  this->error = error;
  TOB::Log::error("Webserver: " + msg);
}
